import re

import fitz  # PyMuPDF
from pathlib import Path
from tests.base_test import base_test_case

logger = base_test_case.get_logger(__name__)
TEST_DATA_DIR = base_test_case.test_data_dir
OUTPUT_DATA_DIR = base_test_case.output_data_dir


def get_pdf_page_by_index(pdf_path: Path, page_index: int) -> fitz.Page:
    """
    根据页码索引（从0开始）从PDF中获取指定页面。

    Args:
        pdf_path (Path): PDF 文件路径。
        page_index (int): 页面索引（0-based）。

    Returns:
        fitz.Page: 指定的页面对象。

    Raises:
        FileNotFoundError: 如果 PDF 文件不存在。
        ValueError: 如果 page_index 超出范围或无效。
        RuntimeError: 如果无法打开 PDF。
    """
    if not pdf_path.exists():
        raise FileNotFoundError(f"PDF 文件不存在: {pdf_path}")

    try:
        doc = fitz.open(pdf_path)
    except Exception as e:
        raise RuntimeError(f"无法打开 PDF 文件 {pdf_path}: {e}")

    total_pages = doc.page_count
    if not (0 <= page_index < total_pages):
        doc.close()
        raise ValueError(f"页码索引 {page_index} 超出范围。PDF 共有 {total_pages} 页（索引 0 到 {total_pages - 1}）。")

    page = doc[page_index]
    # 注意：doc 必须保持打开状态，否则 page 会失效
    # 因此，通常建议在函数外管理 doc 生命周期
    # 但为了简单返回 page，我们这里不关闭 doc —— 实际使用时需注意内存！

    # ⚠️ 重要：返回 page 后，调用方应负责在使用完毕后关闭 doc
    # 更好的做法是返回 (doc, page)，或使用上下文管理器
    # 但为满足“只返回 page”的需求，此处暂不关闭

    return page


# ------------------------------------------------------------
# 动态页码提取函数（简化版，无需坐标）
# ------------------------------------------------------------
def robust_get_page_number(page, area_page_l=None, area_page_r=None):
    """
    尝试从页面中提取页码，优先使用固定区域（如果提供），否则动态检测。
    此处仅实现动态检测部分。
    """
    # 如果提供了固定区域，可在此扩展（略）
    # 本测试 focus 在 area_page_l/r = None 的情况

    blocks = page.get_text("dict").get("blocks", [])
    mediabox = page.rect
    page_height = mediabox.height
    candidates = []

    for block in blocks:
        if "lines" not in block:
            continue
        for line in block["lines"]:
            for span in line["spans"]:
                text = span["text"].strip()
                if not text:
                    continue

                # 提取连续数字（页码通常是纯数字）
                num_match = re.search(r'\d+', text)
                if not num_match:
                    continue

                bbox = fitz.Rect(span["bbox"])
                y_center = (bbox.y0 + bbox.y1) / 2

                # 判断是否在底部 80pt 或顶部 80pt 区域（常见页码位置）
                in_footer = (page_height - y_center) < 80
                in_header = y_center < 80

                if in_footer or in_header:
                    try:
                        num = int(num_match.group())
                        # 简单打分：越靠近边缘越可能是页码
                        score = 0
                        if in_footer:
                            score += 100 - (page_height - y_center)
                        if in_header:
                            score += y_center
                        candidates.append((num, score))
                    except ValueError:
                        continue

    if candidates:
        # 返回得分最高的页码
        best = max(candidates, key=lambda x: x[1])
        return best[0]

    return None


# ----------------------------
# 示例：测试函数
# ----------------------------
if __name__ == "__main__":
    input_pdf = TEST_DATA_DIR / "1711605374231.pdf"
    input_pdf = TEST_DATA_DIR / "1715339805571.pdf"
    target_index = 0  # 获取第3页（0-based）

    try:
        # 打开文档（为了能安全使用 page，必须保持 doc 打开）
        doc = fitz.open(input_pdf)

        for page in doc:
            # 获取页码
            page_number = robust_get_page_number(page=page, area_page_l=None, area_page_r=None)
            print(f"页面页码: {page_number}")

        if not (0 <= target_index < doc.page_count):
            raise ValueError(f"页码 {target_index} 超出范围")
        # page = doc[target_index]

        # 打印信息
        # print(f"成功加载 PDF: {input_pdf}")
        # print(f"请求页码索引: {target_index}（实际第 {target_index + 1} 页）")
        # print(f"页面尺寸 (MediaBox): {page.rect}")
        # print(f"页面文本预览（前100字符）: {page.get_text()[:100].replace(chr(10), ' ').strip()}...")

        # 使用完后记得关闭
        doc.close()

    except Exception as e:
        print(f"❌ 错误: {e}")
